package com.wzcl.app.service.impl;

import com.wzcl.app.dao.model.Activity;
import com.wzcl.app.dao.model.FileGroup;
import com.wzcl.app.dao.repository.FileGroupRepository;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.common.CodeMsg;
import com.wzcl.app.model.common.MyPage;
import com.wzcl.app.model.dto.FileGroupDto;
import com.wzcl.app.service.FileGroupService;
import com.wzcl.app.service.FileModelService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Log4j2
@Service
@Transactional
public class FileGroupServiceImpl implements FileGroupService {

    @Autowired
    private FileGroupRepository repository;

    @Autowired
    private FileModelService fileModelService;

    @Override
    public FileGroup addFileGroup(FileGroupDto fileGroupDto) {
        FileGroup fileGroup = new FileGroup();
        BeanUtils.copyProperties(fileGroupDto, fileGroup);
        checkAndChange(fileGroup, fileGroup.getName());
        return repository.save(fileGroup);
    }

    @Override
    public FileGroup getFileGroupById(Integer id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public FileGroup getAndCheckById(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少素材组Id");
        }
        FileGroup group = getFileGroupById(id);
        if (group == null) {
            throw new BusinessException(CodeMsg.FILE_GROUP_NOT_EXIST);
        }
        return group;
    }

    @Override
    public FileGroup updateFileGroup(FileGroupDto fileGroupDto) {
        //校验获取
        FileGroup group = getAndCheckById(fileGroupDto);
        //更新
        if (!StringUtils.equals(group.getName(), fileGroupDto.getName())) {
            checkAndChange(group, fileGroupDto.getName());
            group = repository.save(group);
        }
        return group;
    }

    @Override
    public void delFileGroup(FileGroupDto fileGroupDto) {
        if (fileGroupDto.getGroupIdList() != null && fileGroupDto.getGroupIdList().size() > 0) {
            List<FileGroup> list = repository.findAllById(fileGroupDto.getGroupIdList());
            if (list != null && list.size() > 0) {
                for (FileGroup group : list) {
                    delFileGroup(group);
                }
            }
            return;
        }
        throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少素材库目标对象");
    }

    /**
     * 删除一个文件夹
     * 删除过程：
     * 1.删除文件夹中的文件夹
     * 2.删除文件夹中下的素材
     * 3.删除这个文件夹
     */
    public void delFileGroup(FileGroup oldGroup) {
        //1.删除文件夹中的文件夹
        List<FileGroup> childList = repository.findAllByParentId(oldGroup.getId());
        if (childList != null && childList.size() > 0) {
            for (FileGroup child : childList) {
                //删除文件夹
                delFileGroup(child);
            }
        }
        //2.删除文件夹中下的素材
        fileModelService.delFileModelByGroupId(oldGroup.getId());
        //3.删除这个文件夹
        repository.delete(oldGroup);
    }

    @Override
    public void copyFileGroup(FileGroupDto fileGroupDto) {
        if (fileGroupDto.getGroupIdList() != null && fileGroupDto.getGroupIdList().size() > 0) {
            if (fileGroupDto.getParentId() != null) {
                getAndCheckById(fileGroupDto.getParentId());
            }
            List<FileGroup> list = repository.findAllById(fileGroupDto.getGroupIdList());
            if (list != null && list.size() > 0) {
                for (FileGroup group : list) {
                    copyFileGroup(group, fileGroupDto.getParentId());
                }
            }
            return;
        }
        throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少素材库目标对象");
    }

    /**
     * 将旧文件夹复制到文件夹中
     * 复制过程：
     * 1.指定位置创建新文件夹
     * 2.将旧文件中的文件夹复制到新文件夹中
     * 3.复制文件夹中的文件
     */
    public void copyFileGroup(FileGroup oldGroup, Integer newParentId) {
        //1.指定位置创建新文件夹
        FileGroup group = new FileGroup();
        BeanUtils.copyProperties(oldGroup, group, "id", "parentId");
        group.setParentId(newParentId);
        checkAndChange(group, group.getName());
        //这个是新文件夹
        FileGroup fileGroup = repository.save(group);
        //2.将旧文件中的文件夹复制到新文件夹中
        List<FileGroup> childList = repository.findAllByParentId(oldGroup.getId());
        if (childList != null && childList.size() > 0) {
            for (FileGroup child : childList) {
                //将文件夹复制到新文件夹中
                copyFileGroup(child, fileGroup.getId());
            }
        }
        //3.复制文件夹中的文件
        fileModelService.copyFileModelAllGroup(oldGroup.getId(), fileGroup.getId());
    }

    @Override
    public void moveFileGroup(FileGroupDto fileGroupDto) {
        if (fileGroupDto.getGroupIdList() != null && fileGroupDto.getGroupIdList().size() > 0) {
            if (fileGroupDto.getParentId() != null) {
                getAndCheckById(fileGroupDto.getParentId());
            }
            List<FileGroup> list = repository.findAllById(fileGroupDto.getGroupIdList());
            if (list != null && list.size() > 0) {
                list.stream().forEach(fileGroup -> fileGroup.setParentId(fileGroupDto.getParentId()));
                repository.saveAll(list);
            }
            return;
        }
        throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少素材库目标对象");
    }

    @Override
    public List<FileGroup> getFileGroupList(FileGroupDto fileGroupDto) {
        return repository.findAll(getSpecification(fileGroupDto), fileGroupDto.getSort());
    }

    @Override
    public MyPage<FileGroup> getFileGroupPage(FileGroupDto fileGroupDto) {
        Page<FileGroup> all = repository.findAll(getSpecification(fileGroupDto), fileGroupDto.getPageable());
        ArrayList<FileGroup> list = new ArrayList<>(all.getContent());
        Collections.reverse(list);
        MyPage<FileGroup> myPage = new MyPage<>();
        myPage.setContent(list);
        myPage.setTotalElements(all.getTotalElements());
        return myPage;
    }

    private void checkAndChange(FileGroup fileGroup, String newName) {
        FileGroup group = null;
        String changeName = newName;
        for (int i = 1; ; i++) {
            if (fileGroup.getParentId() != null) {
                group = repository.findByNameAndParentId(changeName, fileGroup.getParentId());
            } else {
                group = repository.findByNameWithNoParentId(changeName);
            }
            if (group == null) {
                break;
            } else {
                changeName = newName + "(" + i + ")";
            }
        }
        fileGroup.setName(changeName);
    }

    private Specification<FileGroup> getSpecification(FileGroupDto fileGroupDto) {
        return new Specification<FileGroup>() {
            @Override
            public Predicate toPredicate(Root<FileGroup> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (StringUtils.isNotBlank(fileGroupDto.getName())) {
                    predicates.add(criteriaBuilder.like(root.get("name"), "%" + fileGroupDto.getName() + "%"));
                }
                if (fileGroupDto.getParentId() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("parentId"), fileGroupDto.getParentId()));
                } else {
                    predicates.add(criteriaBuilder.isNull(root.get("parentId")));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }


}
